package com.lotus.lqmp.service.biz.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lotus.idaas.sdk.common.UserInfoContext;
import com.lotus.lqmp.base.biz.bean.PageQuery;
import com.lotus.lqmp.base.third.model.CommonUserDTO;
import com.lotus.lqmp.service.biz.ReviewPlanBizService;
import com.lotus.lqmp.service.common.convert.ReviewPlanConvert;
import com.lotus.lqmp.service.common.enums.AuditStatusEnum;
import com.lotus.lqmp.service.common.enums.ErrorCodeEnum;
import com.lotus.lqmp.service.common.enums.JrStageTypeEnum;
import com.lotus.lqmp.service.controller.vo.req.ReviewPlanAddReq;
import com.lotus.lqmp.service.controller.vo.req.ReviewPlanQueryReq;
import com.lotus.lqmp.service.controller.vo.req.ReviewPlanUpdateReq;
import com.lotus.lqmp.service.controller.vo.resp.ReviewPlanDeletedQueryResp;
import com.lotus.lqmp.service.controller.vo.resp.ReviewPlanQueryResp;
import com.lotus.lqmp.service.dao.entity.*;
import com.lotus.lqmp.service.domain.ReviewPlanDeletedQueryDomain;
import com.lotus.lqmp.service.domain.ReviewPlanQueryDomain;
import com.lotus.lqmp.service.service.*;
import com.lotus.platform.common.model.exception.BusinessException;
import com.lotus.platform.common.utils.DateUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * description
 * @author Shuang.Pan2
 * @since 2022/03/31 13:12
 */
@Service
public class ReviewPlanBizServiceImpl implements ReviewPlanBizService {

    @Autowired
    private ReviewPlanService reviewPlanService;

    @Autowired
    private ReviewPlanConvert reviewPlanConvert;

    @Autowired
    private EcuInventoryService ecuInventoryService;

    @Autowired
    private EcuInventoryDetailService ecuInventoryDetailService;

    @Autowired
    private ReviewPlanEcuMasterDataService ecuMasterDataService;

    @Autowired
    private EcuReviewStageRecordService stageRecordService;

    @Autowired
    private UserInfoTransferService userInfoTransferService;

    @Override
    public Page<ReviewPlanQueryResp> queryForPage(PageQuery<ReviewPlanQueryReq> queryInfo) {
        long start = (queryInfo.getPageNum() - 1) * queryInfo.getPageSize();
        List<ReviewPlanQueryDomain> reviewPlanQueryDomainList = reviewPlanService.listForReviewPlanPage(
            queryInfo.getQueryInfo(), start, queryInfo.getPageSize());
        Long total = reviewPlanService.countForReviewPlanPage(queryInfo.getQueryInfo());
        return buildPageData(queryInfo, reviewPlanQueryDomainList, total);
    }

    @Override
    public void add(ReviewPlanAddReq reviewPlanAddReq) {
        //check 未删除的评审中是否已经存在对应的计划
        EcuInventoryDo ecuInventoryDo = ecuInventoryService.getByReviewPlanNo(reviewPlanAddReq.getProjectId());
        if (ecuInventoryDo == null) {
            throw new BusinessException(ErrorCodeEnum.ECU_INVENTORY_NOT_EXIST);
        }

        List<EcuInventoryDetailDo> ecuInventoryDetailDos = ecuInventoryDetailService.getByEcuInventoryId(
            ecuInventoryDo.getId());
        if (CollectionUtils.isEmpty(ecuInventoryDetailDos)) {
            throw new BusinessException(ErrorCodeEnum.ECU_INVENTORY_DETAIL_NOT_EXIST);
        }

        ReviewPlanDo reviewPlanDo = reviewPlanService.getNotDeletedByEcuInventoryId(ecuInventoryDo.getId());
        if (reviewPlanDo != null) {
            throw new BusinessException(ErrorCodeEnum.EXIST_ECU_REVIEW_PLAN_CREATED);
        }

        reviewPlanDo = buildReviewPlanAddInfo(reviewPlanAddReq, ecuInventoryDo);
        //todo 编号生成规则待定
        reviewPlanDo.setReviewPlanNo(generateReviewPlanNo());
        reviewPlanService.save(reviewPlanDo);

        saveReviewPlanEcuInfo(reviewPlanDo, ecuInventoryDetailDos, ecuInventoryDo);
    }

    private String generateReviewPlanNo() {
        long createdNum = reviewPlanService.getTodayCreatedNum() + 1;
        return "PS" + DateUtils.format(new Date(), DateUtils.shortFormat) + StringUtils.leftPad(
            String.valueOf(createdNum), 3, "0");
    }

    @Override
    public void update(ReviewPlanUpdateReq reviewPlanUpdateReq) {
        ReviewPlanDo reviewPlanDo = reviewPlanService.getById(reviewPlanUpdateReq.getId());
        if (reviewPlanDo == null) {
            throw new BusinessException(ErrorCodeEnum.REVIEW_PLAN_NOT_EXIST);
        }

        buildReviewPlanBasicInfo(reviewPlanDo, reviewPlanUpdateReq.getJr1ESeries(), reviewPlanUpdateReq.getJr2ESeries(),
            reviewPlanUpdateReq.getJr3ESeries(), reviewPlanUpdateReq.getJr4ESeries(), reviewPlanUpdateReq.getJr1Mrd(),
            reviewPlanUpdateReq.getJr2Mrd(), reviewPlanUpdateReq.getJr3Mrd(), reviewPlanUpdateReq.getJr4Mrd());
        reviewPlanDo.setEditor(UserInfoContext.getUserInfo().getEmployeeNo());
        reviewPlanService.updateById(reviewPlanDo);
    }

    @Override
    public void batchDeleteByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }

        Long count = reviewPlanService.countNotGoingPlan(ids, AuditStatusEnum.GOING.getStatus());
        if (count == null || count == 0) {
            throw new BusinessException(ErrorCodeEnum.EXIST_GOING_REVIEW_PLAN);
        }

        reviewPlanService.logicBatchDelete(ids);
    }

    @Override
    public Page<ReviewPlanDeletedQueryResp> queryDeletedForPage(PageQuery<ReviewPlanQueryReq> queryInfo) {
        long start = (queryInfo.getPageNum() - 1) * queryInfo.getPageSize();
        List<ReviewPlanDeletedQueryDomain> deletedReviewPlanPage = reviewPlanService.listForDeletedReviewPlanPage(
            queryInfo.getQueryInfo(), start, queryInfo.getPageSize());
        Long total = reviewPlanService.countForDeletedReviewPlanPage(queryInfo.getQueryInfo());
        return buildDeletedPageInfo(deletedReviewPlanPage, total, queryInfo);
    }

    @Override
    public void batchRestore(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }

        //check 未删除中是否已经存在了同样的项目的评审计划
        List<ReviewPlanDo> reviewPlanDos = reviewPlanService.getDeletedPlans(ids);
        if (reviewPlanDos.size() != ids.size()) {
            throw new BusinessException(ErrorCodeEnum.EXIST_NOT_DELETED_REVIEW_PLAN);
        }

        List<Long> ecuInventoryIds = reviewPlanDos.stream().map(ReviewPlanDo::getEcuInventoryId)
            .collect(Collectors.toList());
        reviewPlanDos = reviewPlanService.getNotDeletedByEcuInventoryIds(ecuInventoryIds);
        if (!CollectionUtils.isEmpty(reviewPlanDos)) {
            throw new BusinessException(ErrorCodeEnum.EXIST_ECU_REVIEW_PLAN_CREATED);
        }

        reviewPlanService.batchRestorePlan(ids);
    }

    @Override
    public void clearAll() {
        reviewPlanService.clearAll();
    }

    private Page<ReviewPlanDeletedQueryResp> buildDeletedPageInfo(
        List<ReviewPlanDeletedQueryDomain> deletedQueryDomains, Long total, PageQuery<ReviewPlanQueryReq> queryInfo) {
        Page<ReviewPlanDeletedQueryResp> page = new Page<>(queryInfo.getPageNum(), queryInfo.getPageSize());
        page.setTotal(total == null ? 0L : total);
        Map<String, CommonUserDTO> no2UserInfo = userInfoTransferService.getUserInfoByEmployeeNos(
            getEmpNos(deletedQueryDomains));
        Map<Long, ReviewPlanDeletedQueryDomain> id2Domain = deletedQueryDomains.stream()
            .collect(Collectors.toMap(ReviewPlanDeletedQueryDomain::getId, Function.identity()));
        page.setRecords(reviewPlanConvert.deletedDomains2Resp(deletedQueryDomains));
        page.getRecords().forEach(curr -> {
            curr.setCreator(no2UserInfo.get(id2Domain.get(curr.getId()).getCreator()));
            curr.setEditor(no2UserInfo.get(id2Domain.get(curr.getId()).getCreator()));
        });
        return page;
    }

    private List<String> getEmpNos(List<ReviewPlanDeletedQueryDomain> deletedQueryDomains) {
        List<String> nos = deletedQueryDomains.stream().map(ReviewPlanDeletedQueryDomain::getCreator)
            .collect(Collectors.toList());
        nos.addAll(
            deletedQueryDomains.stream().map(ReviewPlanDeletedQueryDomain::getEditor).collect(Collectors.toList()));
        return nos;
    }

    private void buildReviewPlanBasicInfo(ReviewPlanDo reviewPlanDo, String jr1ESeries, String jr2ESeries,
        String jr3ESeries, String jr4ESeries, Long jr1Mrd, Long jr2Mrd, Long jr3Mrd, Long jr4Mrd) {
        reviewPlanDo.setJr1ESeries(jr1ESeries);
        reviewPlanDo.setJr2ESeries(jr2ESeries);
        reviewPlanDo.setJr3ESeries(jr3ESeries);
        reviewPlanDo.setJr4ESeries(jr4ESeries);

        reviewPlanDo.setJr1Mrd(new Date(jr1Mrd));
        if (!Objects.isNull(jr2Mrd)) {
            reviewPlanDo.setJr1Mrd(new Date(jr2Mrd));
        }
        if (!Objects.isNull(jr3Mrd)) {
            reviewPlanDo.setJr1Mrd(new Date(jr3Mrd));
        }
        if (!Objects.isNull(jr3Mrd)) {
            reviewPlanDo.setJr1Mrd(new Date(jr4Mrd));
        }
    }

    private void saveReviewPlanEcuInfo(ReviewPlanDo reviewPlanDo, List<EcuInventoryDetailDo> ecuInventoryDetailDos,
        EcuInventoryDo ecuInventoryDo) {
        List<ReviewPlanEcuMasterDataDo> ecuMasterDataDos = Lists.newArrayList();
        ecuInventoryDetailDos.forEach(
            ecuInventoryDetailDo -> ecuMasterDataDos.add(buildMasterData(reviewPlanDo, ecuInventoryDetailDo)));

        ecuMasterDataService.saveBatch(ecuMasterDataDos);
        List<EcuReviewStageRecordDo> stageRecordDos = Lists.newArrayList();
        ecuMasterDataDos.forEach(
            ecuMasterDataDo -> stageRecordDos.addAll(buildEcuStageRecordInitInfo(ecuMasterDataDo)));
        stageRecordService.saveBatch(stageRecordDos);
    }

    private ReviewPlanEcuMasterDataDo buildMasterData(ReviewPlanDo reviewPlanDo,
        EcuInventoryDetailDo ecuInventoryDetailDo) {
        ReviewPlanEcuMasterDataDo reviewPlanEcuMasterDataDo = new ReviewPlanEcuMasterDataDo();
        reviewPlanEcuMasterDataDo.setReviewPlanId(reviewPlanDo.getId());
        BeanUtils.copyProperties(ecuInventoryDetailDo, reviewPlanEcuMasterDataDo);
        reviewPlanEcuMasterDataDo.setId(null);
        reviewPlanDo.setCreator(UserInfoContext.getUserInfo().getEmployeeNo());
        reviewPlanDo.setCreateTime(null);
        reviewPlanDo.setUpdateTime(null);
        reviewPlanDo.setEditor(UserInfoContext.getUserInfo().getEmployeeNo());
        return reviewPlanEcuMasterDataDo;
    }

    private List<EcuReviewStageRecordDo> buildEcuStageRecordInitInfo(ReviewPlanEcuMasterDataDo ecuMasterDataDo) {
        List<EcuReviewStageRecordDo> ecuReviewStageRecordDos = Lists.newArrayList();
        ecuReviewStageRecordDos.add(buildJrStageInitInfo(ecuMasterDataDo, JrStageTypeEnum.JR1));
        ecuReviewStageRecordDos.add(buildJrStageInitInfo(ecuMasterDataDo, JrStageTypeEnum.JR2));
        ecuReviewStageRecordDos.add(buildJrStageInitInfo(ecuMasterDataDo, JrStageTypeEnum.JR3));
        ecuReviewStageRecordDos.add(buildJrStageInitInfo(ecuMasterDataDo, JrStageTypeEnum.JR4));
        return ecuReviewStageRecordDos;
    }

    private EcuReviewStageRecordDo buildJrStageInitInfo(ReviewPlanEcuMasterDataDo ecuMasterDataDo,
        JrStageTypeEnum jrStageTypeEnum) {
        EcuReviewStageRecordDo stageRecordDo = new EcuReviewStageRecordDo();
        stageRecordDo.setJrStage(jrStageTypeEnum.getStage());
        stageRecordDo.setCreator(UserInfoContext.getUserInfo().getEmployeeNo());
        stageRecordDo.setEditor(UserInfoContext.getUserInfo().getEmployeeNo());
        stageRecordDo.setReviewPlanEcuBasicInfoId(ecuMasterDataDo.getId());
        return stageRecordDo;
    }

    private ReviewPlanDo buildReviewPlanAddInfo(ReviewPlanAddReq reviewPlanAddReq, EcuInventoryDo ecuInventoryDo) {
        ReviewPlanDo reviewPlanDo = new ReviewPlanDo();
        reviewPlanDo.setEcuInventoryId(ecuInventoryDo.getId());
        buildReviewPlanBasicInfo(reviewPlanDo, reviewPlanAddReq.getJr1ESeries(), reviewPlanAddReq.getJr2ESeries(),
            reviewPlanAddReq.getJr3ESeries(), reviewPlanAddReq.getJr4ESeries(), reviewPlanAddReq.getJr1Mrd(),
            reviewPlanAddReq.getJr2Mrd(), reviewPlanAddReq.getJr3Mrd(), reviewPlanAddReq.getJr4Mrd());
        reviewPlanDo.setTopologyVersion(ecuInventoryDo.getTopologyVersion());
        reviewPlanDo.setCreator(UserInfoContext.getUserInfo().getEmployeeNo());
        reviewPlanDo.setEditor(UserInfoContext.getUserInfo().getEmployeeNo());
        return reviewPlanDo;
    }

    private Page<ReviewPlanQueryResp> buildPageData(PageQuery<ReviewPlanQueryReq> queryInfo,
        List<ReviewPlanQueryDomain> reviewPlanQueryDomainList, Long total) {
        Page<ReviewPlanQueryResp> page = new Page<>(queryInfo.getPageNum(), queryInfo.getPageSize());
        page.setTotal(total == null ? 0L : total);
        page.setRecords(reviewPlanConvert.domains2Resps(reviewPlanQueryDomainList));
        return page;
    }
}
